<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta name="generator" content="pdoc 0.9.1" />
<title>tronpytool.common.datastructures API documentation</title>
<meta name="description" content="" />
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
</head>
<body>
<main>
<article id="content">
<header>
<h1 class="title">Module <code>tronpytool.common.datastructures</code></h1>
</header>
<section id="section-intro">
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">from collections import (
    Hashable,
    Mapping,
    MutableMapping,
    OrderedDict,
    Sequence,
)

from trx_utils import (
    is_integer,
)

from tronpytool.common.formatters import (
    recursive_map,
)

# Hashable must be immutable:
# &#34;the implementation of hashable collections requires that a key&#39;s hash value is immutable&#34;
# https://docs.python.org/3/reference/datamodel.html#object.__hash__


class ReadableAttributeDict(Mapping):
    &#34;&#34;&#34;
    The read attributes for the AttributeDict types
    &#34;&#34;&#34;

    def __init__(self, dictionary, *args, **kwargs):
        self.__dict__ = dict(dictionary)
        self.__dict__.update(dict(*args, **kwargs))

    def __getitem__(self, key):
        return self.__dict__[key]

    def __iter__(self):
        return iter(self.__dict__)

    def __len__(self):
        return len(self.__dict__)

    def __repr__(self):
        return self.__class__.__name__ + &#34;(%r)&#34; % self.__dict__

    def _repr_pretty_(self, builder, cycle):
        &#34;&#34;&#34;
        Custom pretty output for the IPython console
        &#34;&#34;&#34;
        builder.text(self.__class__.__name__ + &#34;(&#34;)
        if cycle:
            builder.text(&#34;&lt;cycle&gt;&#34;)
        else:
            builder.pretty(self.__dict__)
        builder.text(&#34;)&#34;)

    @classmethod
    def _apply_if_mapping(cls, value):
        if isinstance(value, Mapping):
            return cls(value)
        else:
            return value

    @classmethod
    def recursive(cls, value):
        return recursive_map(cls._apply_if_mapping, value)


class MutableAttributeDict(MutableMapping, ReadableAttributeDict):

    def __setitem__(self, key, val):
        self.__dict__[key] = val

    def __delitem__(self, key):
        del self.__dict__[key]


class AttributeDict(ReadableAttributeDict, Hashable):
    &#34;&#34;&#34;
    This provides superficial immutability, someone could hack around it
    &#34;&#34;&#34;

    def __setattr__(self, attr, val):
        if attr == &#39;__dict__&#39;:
            super().__setattr__(attr, val)
        else:
            raise TypeError(&#39;This data is immutable -- create a copy instead of modifying&#39;)

    def __delattr__(self, key):
        raise TypeError(&#39;This data is immutable -- create a copy instead of modifying&#39;)

    def __hash__(self):
        return hash(tuple(sorted(self.items())))

    def __eq__(self, other):
        if isinstance(other, Mapping):
            return self.__dict__ == dict(other)
        else:
            return False


class NamedElementOnion(Mapping):
    &#34;&#34;&#34;
    Add layers to an onion-shaped structure. Optionally, inject to a specific layer.
    This structure is iterable, where the outermost layer is first, and innermost is last.
    &#34;&#34;&#34;
    def __init__(self, init_elements, valid_element=callable):
        self._queue = OrderedDict()
        for element in reversed(init_elements):
            if valid_element(element):
                self.add(element)
            else:
                self.add(*element)

    def add(self, element, name=None):
        if name is None:
            name = element

        if name in self._queue:
            if name is element:
                raise ValueError(&#34;You can&#39;t add the same un-named instance twice&#34;)
            else:
                raise ValueError(&#34;You can&#39;t add the same name again, use replace instead&#34;)

        self._queue[name] = element

    def inject(self, element, name=None, layer=None):
        &#34;&#34;&#34;
        Inject a named element to an arbitrary layer in the onion.

        The current implementation only supports insertion at the innermost layer,
        or at the outermost layer. Note that inserting to the outermost is equivalent
        to calling :meth:`add` .
        &#34;&#34;&#34;
        if not is_integer(layer):
            raise TypeError(&#34;The layer for insertion must be an int.&#34;)
        elif layer != 0 and layer != len(self._queue):
            raise NotImplementedError(
                &#34;You can only insert to the beginning or end of a %s, currently. &#34;
                &#34;You tried to insert to %d, but only 0 and %d are permitted. &#34; % (
                    type(self),
                    layer,
                    len(self._queue),
                )
            )

        self.add(element, name=name)

        if layer == 0:
            if name is None:
                name = element
            self._queue.move_to_end(name, last=False)
        elif layer == len(self._queue):
            return
        else:
            raise AssertionError(&#34;Impossible to reach: earlier validation raises an error&#34;)

    def clear(self):
        self._queue.clear()

    def replace(self, old, new):
        if old not in self._queue:
            raise ValueError(&#34;You can&#39;t replace unless one already exists, use add instead&#34;)
        to_be_replaced = self._queue[old]
        if to_be_replaced is old:
            # re-insert with new name in old slot
            self._replace_with_new_name(old, new)
        else:
            self._queue[old] = new
        return to_be_replaced

    def remove(self, old):
        if old not in self._queue:
            raise ValueError(&#34;You can only remove something that has been added&#34;)
        del self._queue[old]

    def _replace_with_new_name(self, old, new):
        self._queue[new] = new
        found_old = False
        for key in list(self._queue.keys()):
            if not found_old:
                if key == old:
                    found_old = True
                continue
            elif key != new:
                self._queue.move_to_end(key)
        del self._queue[old]

    def __iter__(self):
        elements = self._queue.values()
        if not isinstance(elements, Sequence):
            elements = list(elements)
        return iter(reversed(elements))

    def __add__(self, other):
        if not isinstance(other, NamedElementOnion):
            raise NotImplementedError(&#34;You can only combine with another NamedElementOnion&#34;)
        combined = self._queue.copy()
        combined.update(other._queue)
        return NamedElementOnion(combined.items())

    def __contains__(self, element):
        return element in self._queue

    def __getitem__(self, element):
        return self._queue[element]

    def __len__(self):
        return len(self._queue)

    def __reversed__(self):
        elements = self._queue.values()
        if not isinstance(elements, Sequence):
            elements = list(elements)
        return iter(elements)</code></pre>
</details>
</section>
<section>
</section>
<section>
</section>
<section>
</section>
<section>
<h2 class="section-title" id="header-classes">Classes</h2>
<dl>
<dt id="tronpytool.common.datastructures.AttributeDict"><code class="flex name class">
<span>class <span class="ident">AttributeDict</span></span>
<span>(</span><span>dictionary, *args, **kwargs)</span>
</code></dt>
<dd>
<div class="desc"><p>This provides superficial immutability, someone could hack around it</p></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">class AttributeDict(ReadableAttributeDict, Hashable):
    &#34;&#34;&#34;
    This provides superficial immutability, someone could hack around it
    &#34;&#34;&#34;

    def __setattr__(self, attr, val):
        if attr == &#39;__dict__&#39;:
            super().__setattr__(attr, val)
        else:
            raise TypeError(&#39;This data is immutable -- create a copy instead of modifying&#39;)

    def __delattr__(self, key):
        raise TypeError(&#39;This data is immutable -- create a copy instead of modifying&#39;)

    def __hash__(self):
        return hash(tuple(sorted(self.items())))

    def __eq__(self, other):
        if isinstance(other, Mapping):
            return self.__dict__ == dict(other)
        else:
            return False</code></pre>
</details>
<h3>Ancestors</h3>
<ul class="hlist">
<li><a title="tronpytool.common.datastructures.ReadableAttributeDict" href="#tronpytool.common.datastructures.ReadableAttributeDict">ReadableAttributeDict</a></li>
<li>collections.abc.Mapping</li>
<li>collections.abc.Collection</li>
<li>collections.abc.Sized</li>
<li>collections.abc.Iterable</li>
<li>collections.abc.Container</li>
<li>collections.abc.Hashable</li>
</ul>
</dd>
<dt id="tronpytool.common.datastructures.MutableAttributeDict"><code class="flex name class">
<span>class <span class="ident">MutableAttributeDict</span></span>
<span>(</span><span>dictionary, *args, **kwargs)</span>
</code></dt>
<dd>
<div class="desc"><p>The read attributes for the AttributeDict types</p></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">class MutableAttributeDict(MutableMapping, ReadableAttributeDict):

    def __setitem__(self, key, val):
        self.__dict__[key] = val

    def __delitem__(self, key):
        del self.__dict__[key]</code></pre>
</details>
<h3>Ancestors</h3>
<ul class="hlist">
<li>collections.abc.MutableMapping</li>
<li><a title="tronpytool.common.datastructures.ReadableAttributeDict" href="#tronpytool.common.datastructures.ReadableAttributeDict">ReadableAttributeDict</a></li>
<li>collections.abc.Mapping</li>
<li>collections.abc.Collection</li>
<li>collections.abc.Sized</li>
<li>collections.abc.Iterable</li>
<li>collections.abc.Container</li>
</ul>
</dd>
<dt id="tronpytool.common.datastructures.NamedElementOnion"><code class="flex name class">
<span>class <span class="ident">NamedElementOnion</span></span>
<span>(</span><span>init_elements, valid_element=&lt;built-in function callable&gt;)</span>
</code></dt>
<dd>
<div class="desc"><p>Add layers to an onion-shaped structure. Optionally, inject to a specific layer.
This structure is iterable, where the outermost layer is first, and innermost is last.</p></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">class NamedElementOnion(Mapping):
    &#34;&#34;&#34;
    Add layers to an onion-shaped structure. Optionally, inject to a specific layer.
    This structure is iterable, where the outermost layer is first, and innermost is last.
    &#34;&#34;&#34;
    def __init__(self, init_elements, valid_element=callable):
        self._queue = OrderedDict()
        for element in reversed(init_elements):
            if valid_element(element):
                self.add(element)
            else:
                self.add(*element)

    def add(self, element, name=None):
        if name is None:
            name = element

        if name in self._queue:
            if name is element:
                raise ValueError(&#34;You can&#39;t add the same un-named instance twice&#34;)
            else:
                raise ValueError(&#34;You can&#39;t add the same name again, use replace instead&#34;)

        self._queue[name] = element

    def inject(self, element, name=None, layer=None):
        &#34;&#34;&#34;
        Inject a named element to an arbitrary layer in the onion.

        The current implementation only supports insertion at the innermost layer,
        or at the outermost layer. Note that inserting to the outermost is equivalent
        to calling :meth:`add` .
        &#34;&#34;&#34;
        if not is_integer(layer):
            raise TypeError(&#34;The layer for insertion must be an int.&#34;)
        elif layer != 0 and layer != len(self._queue):
            raise NotImplementedError(
                &#34;You can only insert to the beginning or end of a %s, currently. &#34;
                &#34;You tried to insert to %d, but only 0 and %d are permitted. &#34; % (
                    type(self),
                    layer,
                    len(self._queue),
                )
            )

        self.add(element, name=name)

        if layer == 0:
            if name is None:
                name = element
            self._queue.move_to_end(name, last=False)
        elif layer == len(self._queue):
            return
        else:
            raise AssertionError(&#34;Impossible to reach: earlier validation raises an error&#34;)

    def clear(self):
        self._queue.clear()

    def replace(self, old, new):
        if old not in self._queue:
            raise ValueError(&#34;You can&#39;t replace unless one already exists, use add instead&#34;)
        to_be_replaced = self._queue[old]
        if to_be_replaced is old:
            # re-insert with new name in old slot
            self._replace_with_new_name(old, new)
        else:
            self._queue[old] = new
        return to_be_replaced

    def remove(self, old):
        if old not in self._queue:
            raise ValueError(&#34;You can only remove something that has been added&#34;)
        del self._queue[old]

    def _replace_with_new_name(self, old, new):
        self._queue[new] = new
        found_old = False
        for key in list(self._queue.keys()):
            if not found_old:
                if key == old:
                    found_old = True
                continue
            elif key != new:
                self._queue.move_to_end(key)
        del self._queue[old]

    def __iter__(self):
        elements = self._queue.values()
        if not isinstance(elements, Sequence):
            elements = list(elements)
        return iter(reversed(elements))

    def __add__(self, other):
        if not isinstance(other, NamedElementOnion):
            raise NotImplementedError(&#34;You can only combine with another NamedElementOnion&#34;)
        combined = self._queue.copy()
        combined.update(other._queue)
        return NamedElementOnion(combined.items())

    def __contains__(self, element):
        return element in self._queue

    def __getitem__(self, element):
        return self._queue[element]

    def __len__(self):
        return len(self._queue)

    def __reversed__(self):
        elements = self._queue.values()
        if not isinstance(elements, Sequence):
            elements = list(elements)
        return iter(elements)</code></pre>
</details>
<h3>Ancestors</h3>
<ul class="hlist">
<li>collections.abc.Mapping</li>
<li>collections.abc.Collection</li>
<li>collections.abc.Sized</li>
<li>collections.abc.Iterable</li>
<li>collections.abc.Container</li>
</ul>
<h3>Methods</h3>
<dl>
<dt id="tronpytool.common.datastructures.NamedElementOnion.add"><code class="name flex">
<span>def <span class="ident">add</span></span>(<span>self, element, name=None)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def add(self, element, name=None):
    if name is None:
        name = element

    if name in self._queue:
        if name is element:
            raise ValueError(&#34;You can&#39;t add the same un-named instance twice&#34;)
        else:
            raise ValueError(&#34;You can&#39;t add the same name again, use replace instead&#34;)

    self._queue[name] = element</code></pre>
</details>
</dd>
<dt id="tronpytool.common.datastructures.NamedElementOnion.clear"><code class="name flex">
<span>def <span class="ident">clear</span></span>(<span>self)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def clear(self):
    self._queue.clear()</code></pre>
</details>
</dd>
<dt id="tronpytool.common.datastructures.NamedElementOnion.inject"><code class="name flex">
<span>def <span class="ident">inject</span></span>(<span>self, element, name=None, layer=None)</span>
</code></dt>
<dd>
<div class="desc"><p>Inject a named element to an arbitrary layer in the onion.</p>
<p>The current implementation only supports insertion at the innermost layer,
or at the outermost layer. Note that inserting to the outermost is equivalent
to calling :meth:<code>add</code> .</p></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def inject(self, element, name=None, layer=None):
    &#34;&#34;&#34;
    Inject a named element to an arbitrary layer in the onion.

    The current implementation only supports insertion at the innermost layer,
    or at the outermost layer. Note that inserting to the outermost is equivalent
    to calling :meth:`add` .
    &#34;&#34;&#34;
    if not is_integer(layer):
        raise TypeError(&#34;The layer for insertion must be an int.&#34;)
    elif layer != 0 and layer != len(self._queue):
        raise NotImplementedError(
            &#34;You can only insert to the beginning or end of a %s, currently. &#34;
            &#34;You tried to insert to %d, but only 0 and %d are permitted. &#34; % (
                type(self),
                layer,
                len(self._queue),
            )
        )

    self.add(element, name=name)

    if layer == 0:
        if name is None:
            name = element
        self._queue.move_to_end(name, last=False)
    elif layer == len(self._queue):
        return
    else:
        raise AssertionError(&#34;Impossible to reach: earlier validation raises an error&#34;)</code></pre>
</details>
</dd>
<dt id="tronpytool.common.datastructures.NamedElementOnion.remove"><code class="name flex">
<span>def <span class="ident">remove</span></span>(<span>self, old)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def remove(self, old):
    if old not in self._queue:
        raise ValueError(&#34;You can only remove something that has been added&#34;)
    del self._queue[old]</code></pre>
</details>
</dd>
<dt id="tronpytool.common.datastructures.NamedElementOnion.replace"><code class="name flex">
<span>def <span class="ident">replace</span></span>(<span>self, old, new)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def replace(self, old, new):
    if old not in self._queue:
        raise ValueError(&#34;You can&#39;t replace unless one already exists, use add instead&#34;)
    to_be_replaced = self._queue[old]
    if to_be_replaced is old:
        # re-insert with new name in old slot
        self._replace_with_new_name(old, new)
    else:
        self._queue[old] = new
    return to_be_replaced</code></pre>
</details>
</dd>
</dl>
</dd>
<dt id="tronpytool.common.datastructures.ReadableAttributeDict"><code class="flex name class">
<span>class <span class="ident">ReadableAttributeDict</span></span>
<span>(</span><span>dictionary, *args, **kwargs)</span>
</code></dt>
<dd>
<div class="desc"><p>The read attributes for the AttributeDict types</p></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">class ReadableAttributeDict(Mapping):
    &#34;&#34;&#34;
    The read attributes for the AttributeDict types
    &#34;&#34;&#34;

    def __init__(self, dictionary, *args, **kwargs):
        self.__dict__ = dict(dictionary)
        self.__dict__.update(dict(*args, **kwargs))

    def __getitem__(self, key):
        return self.__dict__[key]

    def __iter__(self):
        return iter(self.__dict__)

    def __len__(self):
        return len(self.__dict__)

    def __repr__(self):
        return self.__class__.__name__ + &#34;(%r)&#34; % self.__dict__

    def _repr_pretty_(self, builder, cycle):
        &#34;&#34;&#34;
        Custom pretty output for the IPython console
        &#34;&#34;&#34;
        builder.text(self.__class__.__name__ + &#34;(&#34;)
        if cycle:
            builder.text(&#34;&lt;cycle&gt;&#34;)
        else:
            builder.pretty(self.__dict__)
        builder.text(&#34;)&#34;)

    @classmethod
    def _apply_if_mapping(cls, value):
        if isinstance(value, Mapping):
            return cls(value)
        else:
            return value

    @classmethod
    def recursive(cls, value):
        return recursive_map(cls._apply_if_mapping, value)</code></pre>
</details>
<h3>Ancestors</h3>
<ul class="hlist">
<li>collections.abc.Mapping</li>
<li>collections.abc.Collection</li>
<li>collections.abc.Sized</li>
<li>collections.abc.Iterable</li>
<li>collections.abc.Container</li>
</ul>
<h3>Subclasses</h3>
<ul class="hlist">
<li><a title="tronpytool.common.datastructures.AttributeDict" href="#tronpytool.common.datastructures.AttributeDict">AttributeDict</a></li>
<li><a title="tronpytool.common.datastructures.MutableAttributeDict" href="#tronpytool.common.datastructures.MutableAttributeDict">MutableAttributeDict</a></li>
</ul>
<h3>Static methods</h3>
<dl>
<dt id="tronpytool.common.datastructures.ReadableAttributeDict.recursive"><code class="name flex">
<span>def <span class="ident">recursive</span></span>(<span>value)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">@classmethod
def recursive(cls, value):
    return recursive_map(cls._apply_if_mapping, value)</code></pre>
</details>
</dd>
</dl>
</dd>
</dl>
</section>
</article>
<nav id="sidebar">
<h1>Index</h1>
<div class="toc">
<ul></ul>
</div>
<ul id="index">
<li><h3>Super-module</h3>
<ul>
<li><code><a title="tronpytool.common" href="index.html">tronpytool.common</a></code></li>
</ul>
</li>
<li><h3><a href="#header-classes">Classes</a></h3>
<ul>
<li>
<h4><code><a title="tronpytool.common.datastructures.AttributeDict" href="#tronpytool.common.datastructures.AttributeDict">AttributeDict</a></code></h4>
</li>
<li>
<h4><code><a title="tronpytool.common.datastructures.MutableAttributeDict" href="#tronpytool.common.datastructures.MutableAttributeDict">MutableAttributeDict</a></code></h4>
</li>
<li>
<h4><code><a title="tronpytool.common.datastructures.NamedElementOnion" href="#tronpytool.common.datastructures.NamedElementOnion">NamedElementOnion</a></code></h4>
<ul class="">
<li><code><a title="tronpytool.common.datastructures.NamedElementOnion.add" href="#tronpytool.common.datastructures.NamedElementOnion.add">add</a></code></li>
<li><code><a title="tronpytool.common.datastructures.NamedElementOnion.clear" href="#tronpytool.common.datastructures.NamedElementOnion.clear">clear</a></code></li>
<li><code><a title="tronpytool.common.datastructures.NamedElementOnion.inject" href="#tronpytool.common.datastructures.NamedElementOnion.inject">inject</a></code></li>
<li><code><a title="tronpytool.common.datastructures.NamedElementOnion.remove" href="#tronpytool.common.datastructures.NamedElementOnion.remove">remove</a></code></li>
<li><code><a title="tronpytool.common.datastructures.NamedElementOnion.replace" href="#tronpytool.common.datastructures.NamedElementOnion.replace">replace</a></code></li>
</ul>
</li>
<li>
<h4><code><a title="tronpytool.common.datastructures.ReadableAttributeDict" href="#tronpytool.common.datastructures.ReadableAttributeDict">ReadableAttributeDict</a></code></h4>
<ul class="">
<li><code><a title="tronpytool.common.datastructures.ReadableAttributeDict.recursive" href="#tronpytool.common.datastructures.ReadableAttributeDict.recursive">recursive</a></code></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</main>
<footer id="footer">
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.9.1</a>.</p>
</footer>
</body>
</html>